/**
 * jdk 线程池 
 * 
在多线程大师Doug Lea的贡献下，在JDK1.5中加入了许多对并发特性的支持，例如：线程池。

一、简介
线程池类为 java.util.concurrent.ThreadPoolExecutor，常用构造方法为：

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler)


corePoolSize： 线程池维护线程的最少数量
maximumPoolSize：线程池维护线程的最大数量
keepAliveTime： 线程池维护线程所允许的空闲时间
unit： 线程池维护线程所允许的空闲时间的单位
workQueue： 线程池所使用的缓冲队列
handler： 线程池对拒绝任务的处理策略

一个任务通过 execute(Runnable)方法被添加到线程池，任务就是一个 Runnable类型的对象，任务的执行方法就是 Runnable类型对象的run()方法。

当一个任务通过execute(Runnable)方法欲添加到线程池时：

如果此时线程池中的数量小于corePoolSize，即使线程池中的线程都处于空闲状态，也要创建新的线程来处理被添加的任务。

如果此时线程池中的数量等于 corePoolSize，但是缓冲队列 workQueue未满，那么任务被放入缓冲队列。

如果此时线程池中的数量大于corePoolSize，缓冲队列workQueue满，并且线程池中的数量小于maximumPoolSize，建新的线程来处理被添加的任务。

如果此时线程池中的数量大于corePoolSize，缓冲队列workQueue满，并且线程池中的数量等于maximumPoolSize，那么通过 handler所指定的策略来处理此任务。

也就是：处理任务的优先级为：
核心线程corePoolSize、任务队列workQueue、最大线程maximumPoolSize，如果三者都满了，使用handler处理被拒绝的任务。

当线程池中的线程数量大于 corePoolSize时，如果某线程空闲时间超过keepAliveTime，线程将被终止。这样，线程池可以动态的调整池中的线程数。

unit可选的参数为java.util.concurrent.TimeUnit中的几个静态属性：
NANOSECONDS、MICROSECONDS、MILLISECONDS、SECONDS。

workQueue我常用的是：java.util.concurrent.ArrayBlockingQueue

handler有四个选择：
ThreadPoolExecutor.AbortPolicy()
抛出java.util.concurrent.RejectedExecutionException异常
ThreadPoolExecutor.CallerRunsPolicy()
重试添加当前的任务，他会自动重复调用execute()方法
ThreadPoolExecutor.DiscardOldestPolicy()
抛弃旧的任务
ThreadPoolExecutor.DiscardPolicy()
抛弃当前的任务 
 * 
 */

package com.cr.backbone.util;

import java.io.Serializable;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy;
import java.util.concurrent.ThreadPoolExecutor.DiscardOldestPolicy;

import javax.mail.internet.MimeMessage;

import org.springframework.mail.SimpleMailMessage;

public class UtilsThreadPoolSendMail {

	private static int produceTaskSleepTime = 2;
	private static int consumeTaskSleepTime = 2000;
	private static int produceTaskMaxNumber = 10;
	private ThreadPoolExecutor threadPool ;//线程池
	protected static UtilsSendMail utilsSendMail;//邮件发送工具

	private static UtilsThreadPoolSendMail instance=new UtilsThreadPoolSendMail();
	
	public UtilsThreadPoolSendMail(){
		int corePoolSize=2;		//维护最小线程数
		int maximumPoolSize=3;	//最大
		long keepAliveTime=2;	//在线线程数
		DiscardOldestPolicy  discardOldestPolicy  = new ThreadPoolExecutor.DiscardOldestPolicy();//拒绝策略，抛弃线程任务
		CallerRunsPolicy  callerRunsPolicy  = new ThreadPoolExecutor.CallerRunsPolicy();//拒绝策略，继续回发线程任务
		// 构造一个线程池
		threadPool = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime,
				TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10),
				callerRunsPolicy);

		//构造一个邮件发送spring mail工具
		utilsSendMail = UtilsSendMail.getInstance();
	}
	
	/**
	 * 获取单例
	 * @methodDescribe
	 * @return
	 * @author xianghua.hu
	 * @date 2012-5-14 
	 */
	public static UtilsThreadPoolSendMail getInstance() {
		if(instance == null ){
			instance = new UtilsThreadPoolSendMail();
		}
		return instance;
	}
	
	/**
	 * 发送普通邮件
	 * @methodDescribe
	 * @param from
	 * @param to
	 * @param subject
	 * @param text
	 * @author xianghua.hu
	 * @date 2012-5-13 下午03:32:55
	 */
	
	public void sendMail(String from,String to,String subject,String text) throws Exception {
		SimpleMailMessage mailMessage=utilsSendMail.initSimpleMailMessage(from, to, subject, text);
		sendMail(mailMessage);
	}
	
	/**
	 * 发送普通邮件
	 * @methodDescribe
	 * @param mailMessage
	 * @author xianghua.hu
	 * @date 2012-5-13 下午03:33:07
	 */
	public void sendMail(SimpleMailMessage mailMessage) {
		instance.threadPool.execute(new ThreadPoolTaskSendMail(mailMessage,utilsSendMail));
	}
	
	
	/**
	 * 发送HTML邮件（支持附件）
	 * @methodDescribe
	 * @param from
	 * @param to
	 * @param subject
	 * @param text
	 * @author xianghua.hu
	 * @date 2012-5-13 下午03:32:55
	 */
	
	public void sendHTMLMail(String from,String to,String subject,String text) throws Exception {
		MimeMessage mailMessage=utilsSendMail.initMimeMailMessage(from, to, subject, text);
		sendHTMLMail(mailMessage);
	}
	
	/**
	 * 发送HTML邮件（支持附件）
	 * @methodDescribe
	 * @param mailMessage
	 * @author xianghua.hu
	 * @date 2012-5-13 下午03:33:07
	 */
	public void sendHTMLMail(MimeMessage mailMessage) {
		instance.threadPool.execute(new ThreadPoolTaskSendHTMLMail(mailMessage,utilsSendMail));
	}
	
	public static void main(String[] args) throws Exception {

		System.out.println("执行发送起始时间:\t"+UtilsDateTime.getCurrentDateTimeString());
		System.out.println("总共内存:\t"+Runtime.getRuntime().totalMemory());
		System.out.println("空闲内存:\t"+Runtime.getRuntime().totalMemory());
		
		
		String from="t37xianghua.hu@gmail.com";
		String to=from;
		String subject;
		String text;
		int i=0;
		while (i<10 ) {
			subject=String.valueOf(i);
			text = new String(UtilsDateTime.getCurrentDateTimeString()+":邮件"+i);
			
			System.out.println("put mail "+i+".." + subject );
			UtilsThreadPoolSendMail.getInstance().sendMail(from, to, subject, text);
			i++;
		}
		
		System.out.println("执行发送结束时间:\t"+UtilsDateTime.getCurrentDateTimeString());
		System.out.println("总共内存:\t"+Runtime.getRuntime().totalMemory());
		System.out.println("空闲内存:\t"+Runtime.getRuntime().totalMemory());
		
		
//		// 构造一个线程池
//		ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 4, 3,
//				TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(3),
//				new ThreadPoolExecutor.DiscardOldestPolicy());
//
//		for (int i = 1; i <= produceTaskMaxNumber; i++) {
//			try {
//				// 产生一个任务，并将其加入到线程池
//				String task = "task@ " + i;
//				System.out.println("put " + task);
//				threadPool.execute(new ThreadPoolTaskSendMail(task,utilsSendMail));
//
//				// 便于观察，等待一段时间
//				Thread.sleep(produceTaskSleepTime);
//			} catch (Exception e) {
//				e.printStackTrace();
//			}
//		}
	}

	/**
	 * 线程池执行的任务demo1
	 * 
	 * @author hdpan
	 */
	public static class ThreadPoolTask implements Runnable, Serializable {
		private static final long serialVersionUID = 0;
		// 保存任务所需要的数据
		private Object threadPoolTaskData;

		ThreadPoolTask(Object tasks) {
			this.threadPoolTaskData = tasks;
		}

		public void run() {
			// 处理一个任务，这里的处理方式太简单了，仅仅是一个打印语句
			System.out.println("start .." + threadPoolTaskData);
			try {
				// //便于观察，等待一段时间
				Thread.sleep(consumeTaskSleepTime);
			} catch (Exception e) {
				e.printStackTrace();
			}
			threadPoolTaskData = null;
		}

		public Object getTask() {
			return this.threadPoolTaskData;
		}
	}


	/**
	 * 线程池执行的任务:邮件发送任务
	 * 
	 * @author huxh
	 */
	public static class ThreadPoolTaskSendMail implements Runnable, Serializable {
		private static final long serialVersionUID = 0;
		// 保存任务所需要的数据
		private SimpleMailMessage threadPoolTaskDataMailMessage;
		private UtilsSendMail utilsSendMail;
		
		
		public ThreadPoolTaskSendMail(SimpleMailMessage tasks, UtilsSendMail utilsSendMail) {
			// TODO Auto-generated constructor stub
			this.threadPoolTaskDataMailMessage = tasks;
			this.utilsSendMail=utilsSendMail;
			System.out.println("\tinit tasks ..\t" + threadPoolTaskDataMailMessage.getSubject());
		}
		
		public void run() {
			// 处理一个任务，这里的处理方式太简单了，仅仅是一个打印语句
//			System.out.println("send mail .." + threadPoolTaskDataMailMessage.getText());
			
			try {
				
				System.out.println("\t\tsend mail ..\t" + threadPoolTaskDataMailMessage.getSubject());
				utilsSendMail.sendMail(threadPoolTaskDataMailMessage);
				
				// //便于观察，等待一段时间
				Thread.sleep(consumeTaskSleepTime);
			} catch (Exception e) {
				e.printStackTrace();
			}
			threadPoolTaskDataMailMessage = null;
		}
		
		public Object getTask() {
			return this.threadPoolTaskDataMailMessage;
		}
	}
	
	/**
	 * 线程池执行的任务:邮件发送任务
	 * 
	 * @author huxh
	 */
	public static class ThreadPoolTaskSendHTMLMail implements Runnable, Serializable {
		private static final long serialVersionUID = 0;
		// 保存任务所需要的数据
		private MimeMessage threadPoolTaskDataHTMLMailMessage;;
		private UtilsSendMail utilsSendMail;


		public ThreadPoolTaskSendHTMLMail(MimeMessage tasks, UtilsSendMail utilsSendMail) {
			// 
			this.threadPoolTaskDataHTMLMailMessage = tasks;
			this.utilsSendMail=utilsSendMail;
		}

		public void run() {
			// 处理一个任务，这里的处理方式太简单了，仅仅是一个打印语句
//			System.out.println("send mail .." + threadPoolTaskDataHTMLMailMessage.getText());
			
			try {
			
				System.out.println("\t\tsend mail ..\t" + threadPoolTaskDataHTMLMailMessage.getSubject());
				
				utilsSendMail.sendMailHtml(threadPoolTaskDataHTMLMailMessage);
				
				// //便于观察，等待一段时间
				Thread.sleep(consumeTaskSleepTime);
			} catch (Exception e) {
				e.printStackTrace();
			}
			threadPoolTaskDataHTMLMailMessage = null;
		}

		public Object getTask() {
			return this.threadPoolTaskDataHTMLMailMessage;
		}
	}

}